

#include <config.h>
#include <gui/renderwidget.h>
#include <math/matrix.h>
#include <stdio.h>
#include <Cg/cg.h>
#include <Cg/cgGL.h>

static void checkForCgError(CGcontext context, const char *situation)
{
  CGerror error;
  const char *string = cgGetLastErrorString(&error);

  if (error != CG_NO_ERROR)
    {
      printf("%s: %s\n", situation, string);
      if (error == CG_COMPILER_ERROR)
        {
          printf("%s\n", cgGetLastListing(context));
        }
    }
}

inka::gui::RenderWidget::RenderWidget(QWidget *parent)
  : QGLWidget(parent)
  , _renderMesh(0)
{
}


void inka::gui::RenderWidget::initializeGL()
{
  glewInit();

  _cgContext = cgCreateContext();
  checkForCgError(_cgContext, "CreateContext");
  _cgVertProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
  _cgFragProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
  checkForCgError(_cgContext, "GotProfiles");

  _cgVertProgram = cgCreateProgramFromFile(
        _cgContext,
        CG_SOURCE,
        CONFIG_PATH "gfx/shaders/lambert_vs.cg",
        _cgVertProfile,
        "main",
        NULL);
  checkForCgError(_cgContext, "CreateVertShader");
  cgGLLoadProgram(_cgVertProgram);
  checkForCgError(_cgContext, "LoadVertShader");

  _cgParamWorldMatrix = cgGetNamedProgramParameter(_cgVertProgram, CG_PROGRAM, "matrix_world");
  _cgParamViewMatrix  = cgGetNamedProgramParameter(_cgVertProgram, CG_PROGRAM, "matrix_view");
  _cgParamProjMatrix  = cgGetNamedProgramParameter(_cgVertProgram, CG_PROGRAM, "matrix_proj");
  _cgParamLightPosition = cgGetNamedProgramParameter(_cgVertProgram, CG_PROGRAM, "light_position");

  _cgFragProgram = cgCreateProgramFromFile(
        _cgContext,
        CG_SOURCE,
        CONFIG_PATH "gfx/shaders/lambert_fs.cg",
        _cgFragProfile,
        "main",
        NULL);
  checkForCgError(_cgContext, "CreateFragShader");
  cgGLLoadProgram(_cgFragProgram);
  checkForCgError(_cgContext, "LoadFragShader");


  for (CGparameter param = cgGetFirstParameter(_cgVertProgram, CG_PROGRAM);
       param;
       param = cgGetNextParameter(param))
    {
      const char* semantic = cgGetParameterSemantic(param);
      const char* name = cgGetParameterName(param);
      printf ("param: %s : %s\n", name, semantic);
      fflush(stdout);
    }


}

void inka::gui::RenderWidget::resizeGL(int w, int h)
{
  glViewport (0, 0, w, h);
}

void inka::gui::RenderWidget::paintGL()
{
  float lightPos [] = { 0.0f, 0.0f, 100.0f, 1.0f };

  inka::math::Matrix4f matWorld;
  inka::math::Matrix4f matView;
  inka::math::Matrix4f matProj;


  glClearColor (0.95f, 0.95f, 0.95f, 1.0f);
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  matWorld.SetIdentity();
  matView.SetLookAt(inka::math::Vector3f (100.0f, 100.0f, 100.0f),
                    inka::math::Vector3f (0.0f, 0.0f, 0.0f),
                    inka::math::Vector3f (0.0f, 0.0f, 1.0f));




  if (width () > height ())
    {
      float aspect = (float)height () / (float)width ();
      matProj.SetPerspective(-1.0f, 1.0f, -aspect, aspect, 1.0f, 1024.0f);
    }
  else
    {
      float aspect =  (float)width() / (float)height();
      matProj.SetPerspective(-aspect, aspect, -1.0f, 1.0f, 1.0f, 1024.0f);
    }


  cgGLBindProgram(_cgVertProgram);
  cgGLEnableProfile(_cgVertProfile);

  cgGLBindProgram(_cgFragProgram);
  cgGLEnableProfile(_cgFragProfile);

  cgGLSetMatrixParameterfc(_cgParamWorldMatrix, (const float*)(matWorld.m));
  cgGLSetMatrixParameterfc(_cgParamViewMatrix, (const float*)(matView.m));
  cgGLSetMatrixParameterfc(_cgParamProjMatrix, (const float*)(matProj.m));
  cgGLSetParameter4fv(_cgParamLightPosition, lightPos);

  if (_renderMesh)
    {
      _renderMesh->Render();
    }
}
